use base64::{engine::general_purpose, Engine as _};
use reqwest::Client;
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use std::collections::HashMap;
use std::error::Error;

#[derive(Debug, Clone)]
pub struct Aria2Client {
    rpc_url: String,
    secret: Option<String>,
    client: Client,
}

#[derive(Debug, Serialize, Deserialize)]
struct JsonRpcRequest {
    jsonrpc: String,
    id: String,
    method: String,
    params: Vec<Value>,
}

#[derive(Debug, Serialize, Deserialize)]
struct JsonRpcResponse {
    id: String,
    jsonrpc: String,
    result: Option<Value>,
    error: Option<JsonRpcError>,
}

#[derive(Debug, Serialize, Deserialize)]
struct JsonRpcError {
    code: i32,
    message: String,
}

impl Aria2Client {
    pub fn new(host: &str, port: u16, secret: Option<String>) -> Self {
        let rpc_url = format!("http://{}:{}/jsonrpc", host, port);
        Aria2Client {
            rpc_url,
            secret,
            client: Client::new(),
        }
    }

    /// 添加Metalink下载
    ///
    /// 通过上传.metalink文件内容添加Metalink下载
    ///
    /// # 参数
    ///
    /// * `metalink` - metalink文件的内容
    /// * `options` - 可选的下载选项
    /// * `position` - 可选的队列位置
    ///
    /// # 返回
    ///
    /// 返回新注册下载的GID数组
    pub async fn add_metalink(
        &self,
        metalink: &[u8],
        options: Option<HashMap<String, Value>>,
        position: Option<usize>,
    ) -> Result<Vec<String>, Box<dyn Error>> {
        // Base64编码metalink内容
        let encoded_metalink = general_purpose::STANDARD.encode(metalink);

        // 构建参数列表
        let mut params = Vec::new();

        // 如果有密钥，添加到参数列表
        if let Some(secret) = &self.secret {
            params.push(json!(secret));
        }

        // 添加metalink内容
        params.push(json!(encoded_metalink));

        // 添加选项（如果有）
        if let Some(opts) = options {
            params.push(json!(opts));
        }

        // 添加位置（如果有）
        if let Some(pos) = position {
            params.push(json!(pos));
        }

        // 发送RPC请求
        let response = self.send_request("aria2.addMetalink", params).await?;

        // 解析结果
        if let Some(result) = response.result {
            if let Some(gids) = result.as_array() {
                let gid_vec = gids
                    .iter()
                    .filter_map(|v| v.as_str().map(String::from))
                    .collect();
                return Ok(gid_vec);
            }
        }

        if let Some(error) = response.error {
            return Err(format!("Aria2 RPC错误: {} ({})", error.message, error.code).into());
        }

        Err("无法解析Aria2响应".into())
    }

    /// 发送JSON-RPC请求到aria2
    async fn send_request(
        &self,
        method: &str,
        params: Vec<Value>,
    ) -> Result<JsonRpcResponse, Box<dyn Error>> {
        let request = JsonRpcRequest {
            jsonrpc: "2.0".to_string(),
            id: "spark-store".to_string(),
            method: method.to_string(),
            params,
        };

        let response = self
            .client
            .post(&self.rpc_url)
            .json(&request)
            .send()
            .await?
            .json::<JsonRpcResponse>()
            .await?;

        Ok(response)
    }

    /// 获取下载状态
    pub async fn tell_status(&self, gid: &str) -> Result<Value, Box<dyn Error>> {
        let mut params = Vec::new();

        if let Some(secret) = &self.secret {
            params.push(json!(secret));
        }

        params.push(json!(gid));

        let response = self.send_request("aria2.tellStatus", params).await?;

        if let Some(result) = response.result {
            return Ok(result);
        }

        if let Some(error) = response.error {
            return Err(format!("Aria2 RPC错误: {} ({})", error.message, error.code).into());
        }

        Err("无法获取下载状态".into())
    }

    /// 获取所有活动中的下载任务
    ///
    /// 返回所有正在下载的任务的状态信息
    ///
    /// # 返回
    ///
    /// 返回包含所有活动下载任务信息的数组
    pub async fn tell_active(&self) -> Result<Vec<Value>, Box<dyn Error>> {
        let mut params = Vec::new();

        if let Some(secret) = &self.secret {
            params.push(json!(secret));
        }

        let response = self.send_request("aria2.tellActive", params).await?;

        if let Some(result) = response.result {
            if let Some(downloads) = result.as_array() {
                return Ok(downloads.clone());
            }
        }

        if let Some(error) = response.error {
            return Err(format!("Aria2 RPC错误: {} ({})", error.message, error.code).into());
        }

        Err("无法获取活动下载任务".into())
    }

    /// 获取等待中的下载任务
    ///
    /// 返回等待队列中的下载任务状态信息
    ///
    /// # 参数
    ///
    /// * `offset` - 从队列开始位置的偏移量
    /// * `num` - 要获取的任务数量
    ///
    /// # 返回
    ///
    /// 返回包含等待中下载任务信息的数组
    pub async fn tell_waiting(
        &self,
        offset: usize,
        num: usize,
    ) -> Result<Vec<Value>, Box<dyn Error>> {
        let mut params = Vec::new();

        if let Some(secret) = &self.secret {
            params.push(json!(secret));
        }

        params.push(json!(offset));
        params.push(json!(num));

        let response = self.send_request("aria2.tellWaiting", params).await?;

        if let Some(result) = response.result {
            if let Some(downloads) = result.as_array() {
                return Ok(downloads.clone());
            }
        }

        if let Some(error) = response.error {
            return Err(format!("Aria2 RPC错误: {} ({})", error.message, error.code).into());
        }

        Err("无法获取等待中的下载任务".into())
    }

    /// 获取已停止的下载任务
    ///
    /// 返回已完成/错误/已移除的下载任务状态信息
    ///
    /// # 参数
    ///
    /// * `offset` - 从队列开始位置的偏移量
    /// * `num` - 要获取的任务数量
    ///
    /// # 返回
    ///
    /// 返回包含已停止下载任务信息的数组
    pub async fn tell_stopped(
        &self,
        offset: usize,
        num: usize,
    ) -> Result<Vec<Value>, Box<dyn Error>> {
        let mut params = Vec::new();

        if let Some(secret) = &self.secret {
            params.push(json!(secret));
        }

        params.push(json!(offset));
        params.push(json!(num));

        let response = self.send_request("aria2.tellStopped", params).await?;

        if let Some(result) = response.result {
            if let Some(downloads) = result.as_array() {
                return Ok(downloads.clone());
            }
        }

        if let Some(error) = response.error {
            return Err(format!("Aria2 RPC错误: {} ({})", error.message, error.code).into());
        }

        Err("无法获取已停止的下载任务".into())
    }

    /// 暂停下载任务
    ///
    /// 暂停指定GID的下载任务
    ///
    /// # 参数
    ///
    /// * `gid` - 下载任务的GID
    ///
    /// # 返回
    ///
    /// 成功时返回被暂停的GID
    pub async fn pause(&self, gid: &str) -> Result<String, Box<dyn Error>> {
        let mut params = Vec::new();

        if let Some(secret) = &self.secret {
            params.push(json!(secret));
        }

        params.push(json!(gid));

        let response = self.send_request("aria2.pause", params).await?;

        if let Some(result) = response.result {
            if let Some(paused_gid) = result.as_str() {
                return Ok(paused_gid.to_string());
            }
        }

        if let Some(error) = response.error {
            return Err(format!("Aria2 RPC错误: {} ({})", error.message, error.code).into());
        }

        Err("无法暂停下载任务".into())
    }

    /// 恢复下载任务
    ///
    /// 恢复指定GID的下载任务
    ///
    /// # 参数
    ///
    /// * `gid` - 下载任务的GID
    ///
    /// # 返回
    ///
    /// 成功时返回被恢复的GID
    pub async fn unpause(&self, gid: &str) -> Result<String, Box<dyn Error>> {
        let mut params = Vec::new();

        if let Some(secret) = &self.secret {
            params.push(json!(secret));
        }

        params.push(json!(gid));

        let response = self.send_request("aria2.unpause", params).await?;

        if let Some(result) = response.result {
            if let Some(unpaused_gid) = result.as_str() {
                return Ok(unpaused_gid.to_string());
            }
        }

        if let Some(error) = response.error {
            return Err(format!("Aria2 RPC错误: {} ({})", error.message, error.code).into());
        }

        Err("无法恢复下载任务".into())
    }

    /// 删除下载任务
    ///
    /// 删除指定GID的下载任务
    ///
    /// # 参数
    ///
    /// * `gid` - 下载任务的GID
    ///
    /// # 返回
    ///
    /// 成功时返回被删除的GID
    pub async fn remove(&self, gid: &str) -> Result<String, Box<dyn Error>> {
        let mut params = Vec::new();

        if let Some(secret) = &self.secret {
            params.push(json!(secret));
        }

        params.push(json!(gid));

        let response = self.send_request("aria2.remove", params).await?;

        if let Some(result) = response.result {
            if let Some(removed_gid) = result.as_str() {
                return Ok(removed_gid.to_string());
            }
        }

        if let Some(error) = response.error {
            return Err(format!("Aria2 RPC错误: {} ({})", error.message, error.code).into());
        }

        Err("无法删除下载任务".into())
    }
}
